package dao

import (
	"context"
	"errors"
	"ruoyi-go-echo-ddd/internal/domain/model"
	"ruoyi-go-echo-ddd/internal/infrastructure/http/request"
	"ruoyi-go-echo-ddd/internal/infrastructure/persistence/config"
	"ruoyi-go-echo-ddd/internal/infrastructure/utils"

	"github.com/rs/zerolog"
	"gorm.io/gorm"
)

// SysPostDaoImpl 岗位信息Dao实现结构体
type SysPostDaoImpl struct {
	db config.PrimaryDB
}

// NewSysPostDaoImpl 岗位信息Dao实现创建
func NewSysPostDaoImpl(db config.PrimaryDB) *SysPostDaoImpl {
	return &SysPostDaoImpl{
		db: db,
	}
}

func (dao *SysPostDaoImpl) Insert(ctx context.Context, sysPost *model.SysPost) (*model.SysPost, error) {
	if err := dao.db.WithContext(ctx).Create(&sysPost).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("岗位信息新增异常===")
		return nil, errors.New("岗位信息新增失败")
	}
	// 如果这里边有使用钩子函数，那么这里需要重新查询而不是直接返回sysPost
	insertPost, err := dao.SelectById(ctx, sysPost.Id)
	if err != nil {
		return nil, errors.New("岗位信息新增失败")
	}
	return insertPost, nil
}

func (dao *SysPostDaoImpl) Update(ctx context.Context, sysPost *model.SysPost) (int64, error) {
	// 主键默认是id，就不需要加上条件
	result := dao.db.WithContext(ctx).
		// Where("id = ?", sysPost.Id).
		Omit("id").
		Save(&sysPost)
	if result.Error != nil {
		return 0, errors.New("岗位信息修改失败")
	}

	return result.RowsAffected, nil
}

func (dao *SysPostDaoImpl) BatchInsert(ctx context.Context, list []*model.SysPost) ([]int64, error) {
	if len(list) <= 0 {
		return nil, errors.New("岗位信息批量新增参数验证失败")
	}

	result := dao.db.WithContext(ctx).CreateInBatches(list, 50)
	if result.Error != nil {
		return nil, errors.New("岗位信息批量新增失败")
	}

	var ids []int64
	for _, item := range list {
		ids = append(ids, item.Id)
	}

	return ids, nil
}

func (dao *SysPostDaoImpl) SelectById(ctx context.Context, id int64) (*model.SysPost, error) {
	var sysPost *model.SysPost
	// 主键为id的时候First(&sysPost, id)默认使用主键ID查询
	if err := dao.db.WithContext(ctx).Model(&model.SysPost{}).First(&sysPost, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("岗位信息未找到")
		}
		zerolog.DefaultContextLogger.Error().Err(err).Msg("岗位信息查询异常===")
		return nil, errors.New("岗位信息查询失败")
	}
	return sysPost, nil
}

func (dao *SysPostDaoImpl) SelectPage(ctx context.Context, param *request.PostPageParam) ([]*model.SysPost, int64, int64, error) {
	pageParam := utils.InitPageParam(param.Page, param.Size)

	// 初始化 GORM db
	db := dao.db.WithContext(ctx).Model(&model.SysPost{})

	if param.PostName != "" {
		db.Where("post_name ILIKE ?", "%"+param.PostName+"%")
	}

	if param.PostCode != "" {
		db.Where("post_code ILIKE ?", "%"+param.PostCode+"%")
	}

	if param.PostStatus != "" {
		db.Where("post_status = ?", param.PostStatus)
	}

	// 时间范围处理
	if param.BeginTime != "" && param.EndTime != "" {
		if begin, end, err := utils.ParseTimeRange(param.BeginTime, param.EndTime); err == nil {
			db.Where("create_time BETWEEN ? AND ?", begin, end)
		}
	}

	// 查询总记录数
	var total int64
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, 0, errors.New("获取岗位信息总记录数失败")
	}


	// 查询用户列表
	var list []*model.SysPost
	if err := utils.SetOrder(db, param.Column, param.Order).
		Offset(int(pageParam.Offset)).Limit(int(pageParam.Size)).
		Find(&list).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("岗位分页查询异常===")
		return nil, 0, 0, errors.New("获取岗位信息列表失败")
	}

	return list, total, utils.CalcTotalPage(total, param.Size), nil
}

func (dao *SysPostDaoImpl) BatchDelete(ctx context.Context, ids []any) (int64, error) {
	if len(ids) <= 0 {
		return 0, errors.New("岗位信息批量删除参数验证失败")
	}
	result := dao.db.WithContext(ctx).Model(&model.SysPost{}).Where("id IN (?)", ids).Delete(nil)
	if result.Error != nil {
		return 0, errors.New("批量删除失败")
	}
	return result.RowsAffected, nil
}

//goland:noinspection SqlResolve,SqlCaseVsIf,SqlNoDataSourceInspection
func (dao *SysPostDaoImpl) SelectPostIdsByUserId(ctx context.Context, userId int64) ([]int64, error) {
	var postIds []int64
	querySql := `SELECT post_id FROM sys_user_post WHERE user_id = ?`
	if err := dao.db.WithContext(ctx).Raw(querySql, userId).Find(&postIds).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("查询用户岗位ID切片错误===")
		return nil, errors.New("查询用户岗位失败")
	}
	return postIds, nil
}

//goland:noinspection SqlResolve,SqlCaseVsIf,SqlNoDataSourceInspection
func (dao *SysPostDaoImpl) SelectPostNameListByIds(ctx context.Context, ids []int64) ([]string, error) {
	var postNameList []string
	querySql := `SELECT post_name FROM sys_post WHERE id IN ?`
	if err := dao.db.WithContext(ctx).Raw(querySql, ids).Find(&postNameList).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("查询用户岗位名称切片错误===")
		return nil, errors.New("查询用户岗位名称失败")
	}
	return postNameList, nil
}

func (dao *SysPostDaoImpl) SelectAll(ctx context.Context) ([]*model.SysPost, error) {
	var (
		list    []*model.SysPost
		allData []*model.SysPost
		count   int64
		page    = 1
		size    = 5000
	)
	db := dao.db.WithContext(ctx).Model(&model.SysPost{})
	if err := db.Count(&count).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("获取岗位总条数错误")
		return nil, errors.New("获取岗位总条数失败")
	}
	zerolog.DefaultContextLogger.Info().Msgf("获取岗位总条数===%d,当前分页批数===%d", count, size)

	// 分页大小大于或等于总条数，则直接一次性查询
	if int64(size) >= count {
		if err := db.Find(&allData).Error; err != nil {
			zerolog.DefaultContextLogger.Error().Err(err).Msg("获取岗位分页错误")
			return nil, errors.New("获取岗位分页失败")
		}
		zerolog.DefaultContextLogger.Info().Msgf("分页大小大于或等于总条数一次性查询所有数据的条数===%d", len(allData))
		return allData, nil
	}

	for {
		list = list[:0]
		if err := db.Limit(size).Offset((page - 1) * size).Find(&list).Error; err != nil {
			zerolog.DefaultContextLogger.Error().Err(err).Msg("获取岗位分页错误")
			return nil, errors.New("获取岗位分页失败")
		}

		zerolog.DefaultContextLogger.Info().Msgf("第%d次岗位分页条数===%d", page, len(list))

		if len(list) == 0 {
			zerolog.DefaultContextLogger.Info().Msgf("第%d次岗位分页条数为0退出循环", page)
			// 无更多数据，退出循环
			break
		}
		allData = append(allData, list...)
		page++
	}
	return allData, nil
}

//goland:noinspection SqlResolve,SqlCaseVsIf,SqlNoDataSourceInspection
func (dao *SysPostDaoImpl) DeleteByUserId(ctx context.Context, userId int64) (int64, error) {
	result := dao.db.WithContext(ctx).Model(&model.SysPost{}).Where("user_id = ?", userId).Delete(nil)
	if result.Error != nil {
		zerolog.DefaultContextLogger.Error().Err(result.Error).Msgf("岗位==%d删除错误", userId)
		return 0, errors.New("岗位删除失败")
	}
	return result.RowsAffected, nil
}

//goland:noinspection SqlResolve,SqlCaseVsIf,SqlNoDataSourceInspection
func (dao *SysPostDaoImpl) DeleteByUserIdList(ctx context.Context, userIds []int64) (int64, error) {
	result := dao.db.WithContext(ctx).Model(&model.SysPost{}).Where("user_id in ?", userIds).Delete(nil)
	if result.Error != nil {
		zerolog.DefaultContextLogger.Error().Err(result.Error).Msgf("岗位===%v删除错误", userIds)
		return 0, errors.New("岗位删除失败")
	}
	return result.RowsAffected, nil
}
